-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
--         http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local class = require 'mc.class'
local log = require 'mc.logging'
local skynet = require 'skynet'
local mdb = require 'mc.mdb'

local FRUCTRL_ITF<const> = 'bmc.kepler.Systems.FruCtrl'

local agent = class()

-- 从资源树上获取电源状态
function agent:get_power_status(system_id)
    local path = "/bmc/kepler/Systems/" .. system_id .. "/FruCtrl"
    local ok, obj_list = pcall(mdb.get_sub_objects, self.bus, path, FRUCTRL_ITF)
    if not ok or not next(obj_list) then
        log:error("get fructrl object failed")
        return nil
    end
    for _, obj in pairs(obj_list) do
        return obj.PowerState
    end
end

function agent:process_update_info_fail(parameters, prop_name)
    if self.hysteresis == 0 then
        log:error("%s: get retimer %s info failed", self.name, prop_name)
        self.retimer.retimer_obj[prop_name] = parameters[prop_name]
        self.retimer.retimer_obj["HealthStatus"] = 1
        return
    end
    self.hysteresis = self.hysteresis - 1
end

function agent:update_retimer_info(parameters)
    local flag = true
    for prop_name, params in pairs(parameters) do
        local ok, msg = params.fun(self.protocol, params.args)
        if ok then
            self.hysteresis = 2
            self.retimer.retimer_obj["HealthStatus"] = 0
            self.retimer.retimer_obj[prop_name] = params.callback(msg)
            log:debug('%s: get retimer %s: %s', self.name, prop_name, self.retimer.retimer_obj[prop_name])
        else
            flag = false
            -- 处理retimer获取信息失败场景
            self:process_update_info_fail(self.PARAMETERS.FAILURE_VALUE, prop_name)
            break
        end
    end
    return flag
end

function agent:retimer_power_off_task(parameters)
    -- 开始下电，start_monitor_flag需置为false，且将温度属性替换为默认值
    if self.start_monitor_flag then
        log:notice('fructrl power status is not ON, retimer monitor task will try later')
        self.start_monitor_flag = false
        for prop_name, params in pairs(parameters) do
            self.retimer.retimer_obj[prop_name] = params
        end
    end
    -- 迟滞量与芯片状态置为默认值，防止下电后告警无法消除
    self.hysteresis = 2
    self.retimer.retimer_obj["HealthStatus"] = 0
    self.retimer:update_firmware_severity()
end

function agent:retimer_power_on_task()
    if not self:judge_retimer_ready() then
        self:retimer_power_off_task(self.PARAMETERS.DEFAULT_VALUE)
        return
    end
    -- 开始上电，需要重新获取固有属性
    if not self.start_monitor_flag then
        -- 刚完成fructrl上电，需要等待retimer就位
        skynet.sleep(500)
        -- 更新Retimer的固有属性信息，如版本信息
        local ok, flag = pcall(
            self.update_retimer_info, self, self.PARAMETERS.PARAMETERS_INHERENT
        )

        -- 固有属性获取成功，并更新fw_mgmt资源树属性Version
        if ok and flag then
            self.start_monitor_flag = true
            log:debug('update firmware version succeed')
        else
            log:error('%s get retimer inherent properties failed', self.name)
            self.retimer:update_firmware_severity()
        end
        self.retimer:update_firmware_version()
    end
end

function agent:retimer_monitor_task()
    if not self.start_monitor_flag then
        return
    end
    -- 获取Retimer的温度等属性
    pcall(function()
        self:update_retimer_info(self.PARAMETERS.PARAMETERS_DYNAMIC)
    end)
end

function agent:judge_retimer_ready()
    if self:get_power_status(1) ~= "ON" then
        return false
    end
    return true
end

function agent:start()
    if self.monitor_task then
        return
    end
    self.monitor_task = skynet.fork_loop({count = 0}, function()
        while true do
            -- 执行上电判断与固有属性的获取
            self:retimer_power_on_task()
            -- 执行温度等属性的监控任务
            self:retimer_monitor_task()
            -- 500, 5秒执行一次
            skynet.sleep(500)
        end
    end)
end

function agent:stop()
    if self.monitor_task then
        skynet.killthread(self.monitor_task)
        self.monitor_task = nil
    end
    self.hysteresis = 2
    self.start_monitor_flag = false
end

function agent:ctor(retimer, bus)
    self.name = retimer.name
    self.retimer = retimer
    self.bus = bus
    self.log_list = {}
    self.start_monitor_flag = false
    self.hysteresis = 2
end

function agent:init(smbus, parameters)
    self.smbus = smbus
    self.PARAMETERS = parameters
    self.protocol = self.smbus.new(self.retimer.retimer_obj.RefChip)
end

return agent
